import { BaseService } from '@/core/base.service';
import {
  RightsInvoiceDispatchDto,
  RightsInvoiceQueryDto,
  RightsListDto,
  RightsQueryDto,
} from '@/dtos';
import { InvoiceOrderStatusEnum } from '@/enums';
import { Injectable } from '@nestjs/common';
import { Prisma, Rights, UserReceiveRights } from '@prisma/client';
import dayjs from 'dayjs';

@Injectable()
export class RightsService extends BaseService {
  async list({ params, sort }: RightsListDto) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
            SELECT #{fields} FROM \`Rights\` AS t
            WHERE t.isDeleted = false
              AND t.isEnabled = true
        `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(t.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<Rights[]>(
      `${sql.replace(
        '#{fields}',
        `
          t.id, t.discount, t.isNeedBurn
        `,
      )}
        ORDER BY ${
          !!sort && Object.keys(sort).length > 0
            ? Object.entries(sort)
                .map(([k, v]) => `t.${k} ${v === 'descend' ? 'DESC' : 'ASC'}`)
                .join(',')
            : 't.createdAt DESC'
        }
        LIMIT ${pageSize} 
        OFFSET ${(current - 1) * pageSize}
    `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list: list.map((o) => ({
        ...o,
      })),
    };
  }

  async query({ params, sort }: RightsQueryDto) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
            SELECT #{fields} FROM \`Rights\` AS t
            WHERE t.isDeleted = false
        `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(t.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<Rights[]>(
      `${sql.replace(
        '#{fields}',
        `
            t.id, t.discount, t.isNeedBurn, t.isEnabled, t.createdAt
        `,
      )}
            ORDER BY ${
              !!sort && Object.keys(sort).length > 0
                ? Object.entries(sort)
                    .map(
                      ([k, v]) => `t.${k} ${v === 'descend' ? 'DESC' : 'ASC'}`,
                    )
                    .join(',')
                : 't.createdAt DESC'
            }
            LIMIT ${pageSize}
            OFFSET ${(current - 1) * pageSize}
        `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list: list.map((o) => ({
        ...o,
      })),
    };
  }

  async findOne(
    where: Prisma.RightsWhereUniqueInput,
    select?: Prisma.RightsSelect,
  ): Promise<Rights | null> {
    return this.prisma.rights.findUnique({
      where,
      select,
    });
  }

  async create(data: Prisma.RightsCreateInput): Promise<Rights> {
    return await this.prisma.rights.create({
      data: {
        ...data,
      },
    });
  }

  async update(params: {
    where: Prisma.RightsWhereUniqueInput;
    data: Prisma.RightsUpdateInput;
  }): Promise<Rights> {
    const { where, data } = params;
    return this.prisma.rights.update({
      where,
      data: {
        ...data,
      },
    });
  }

  async invoice({ params, sort }: RightsInvoiceQueryDto) {
    const { current = 1, pageSize = 20, keyword, ...where } = params;

    let sql = `
      SELECT #{fields} FROM UserReceiveRights AS t
      LEFT JOIN User AS u ON u.id = t.userId
      LEFT JOIN Token AS tk ON tk.id = t.tokenId
      LEFT JOIN Asset AS a ON a.id = tk.assetId
      WHERE t.isDeleted = false
        ${!!where.status ? `AND t.status = ${where.status}` : ''}
        ${!!where.assetId ? `AND a.id = ${where.assetId}` : ''}
        ${!!where.realname ? `AND u.realname LIKE '%${where.realname}%'` : ''}
        ${!!where.mobile ? `AND u.mobile LIKE '%${where.mobile}%'` : ''}
        ${!!where.startTime ? `AND CONVERT_TZ(t.createdAt, 'UTC', 'Asia/Shanghai') >= '${where.startTime}'` : ''}
        ${!!where.endTime ? `AND CONVERT_TZ(t.createdAt, 'UTC', 'Asia/Shanghai') <= '${where.endTime}'` : ''}
    `;

    const [{ count }] = await this.prisma.$queryRawUnsafe<[{ count: number }]>(
      sql.replace('#{fields}', 'COUNT(t.id) AS count'),
    );

    const list = await this.prisma.$queryRawUnsafe<UserReceiveRights[]>(
      `${sql.replace(
        '#{fields}',
        `
          t.id, t.express, t.address, t.status, a.title, tk.no,
          u.realname, u.mobile, t.createdAt
        `,
      )}
      ORDER BY ${
        !!sort && Object.keys(sort).length > 0
          ? Object.entries(sort)
              .map(([k, v]) => `t.${k} ${v === 'descend' ? 'DESC' : 'ASC'}`)
              .join(',')
          : 't.createdAt DESC'
      }
      LIMIT ${pageSize} 
      OFFSET ${(current - 1) * pageSize}
      `,
    );

    const total = count ? Number(count) : 0;
    const totalPage = Math.ceil(total / pageSize);
    const hasMore = current < totalPage;

    return {
      total,
      totalPage,
      hasMore,
      current,
      pageSize,
      list,
    };
  }

  async dispatch({
    id,
    no,
  }: RightsInvoiceDispatchDto): Promise<UserReceiveRights> {
    return this.prisma.userReceiveRights.update({
      where: {
        id,
      },
      data: {
        status: InvoiceOrderStatusEnum.COMPLETED,
        express: {
          no,
          date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
        },
      },
    });
  }
}
